<template>
  <div id="three">
    <ThreePicker
      :camera="camera"
      :container="container"
      :geometries="canvasContent.geometries"
      :render="render"
    ></ThreePicker>
  </div>
</template>

<script>
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

import ThreePicker from "./ThreePicker.vue";

import eventBus from "../utils/EventBus";
import {
  THREE_CANVAS_DRAW,
  THREE_CANVAS_DELETE,
  THREE_CANVAS_REFRESH,
  SET_VIEW_TO_ALL,
  SET_VIEW_TO_FRONT,
  SET_VIEW_TO_RIGHT,
  SET_VIEW_TO_TOP,
  SET_SAVE_TO_PICTURE,
} from "../utils/EventBus/events";

import { createBox3 } from "../utils/Tools/ThreeTools";

export default {
  name: "three-canvas",
  components: { ThreePicker },
  data() {
    return {
      canvasWidth: 0,
      canvasHeight: 0,

      container: null,
      scene: null,
      camera: null,
      renderer: null,
      controls: null,

      canvasPositionInfo: {
        maxSize: undefined,
        maxPosition: undefined,
        xRange: {
          max: undefined,
          min: undefined,
        },
        yRange: {
          max: undefined,
          min: undefined,
        },
        zRange: {
          max: undefined,
          min: undefined,
        },
      },
      canvasContent: {
        basics: {
          axesHelper: null,
          ground: null,
          light: null,
        },
        geometries: [],
      },
    };
  },
  mounted() {
    // 获取画布尺寸和DOM
    this.getCanvasSize();
    // 初始化三维环境
    this.initThree();
    // 加载画布内容
    this.loadContent();
    // 添加光源
    this.createLight();
    // 切换至总览视图
    if (this.canvasContent.geometries.length) {
      this.moveCameraToAll();
    }
    // 绑定窗口尺寸变动事件
    window.addEventListener("resize", this.resizeEvent);

    // 全局事件与回调函数接口
    eventBus.$on(THREE_CANVAS_DRAW, (g) => {
      this.drawGeometry(g);
    });
    eventBus.$on(THREE_CANVAS_DELETE, (id) => {
      this.deleteGeometry(id);
    });
    eventBus.$on(THREE_CANVAS_REFRESH, () => {
      this.updateGeometries();
    });
    eventBus.$on(SET_VIEW_TO_ALL, () => {
      this.moveCameraToAll();
    });
    eventBus.$on(SET_VIEW_TO_FRONT, () => {
      this.moveCameraToFront();
    });
    eventBus.$on(SET_VIEW_TO_RIGHT, () => {
      this.moveCameraToRight();
    });
    eventBus.$on(SET_VIEW_TO_TOP, () => {
      this.moveCameraToTop();
    });
    eventBus.$on(SET_SAVE_TO_PICTURE, () => {
      this.saveCanvasTOPicture();
    })
    eventBus.$api.getCanvasGeometrieById = (index) => {
      return this.canvasContent.geometries[index];
    };
  },
  watch: {
    // 监听 maxSize 改变时更新坐标系长度
    "canvasPositionInfo.maxSize": {
      handler(val) {
        if (val === undefined) return;
        this.updateAxesHelper(val * 1.5);
      },
      immediate: true,
    },
  },
  computed: {
    // 计算地面尺寸
    groundSize() {
      if (this.canvasPositionInfo.xRange.max === undefined)
        return { w: 0, h: 0 };
      const w =
        this.canvasPositionInfo.xRange.max - this.canvasPositionInfo.xRange.min;
      const h =
        this.canvasPositionInfo.zRange.max - this.canvasPositionInfo.zRange.min;
      return { w, h };
    },
  },
  methods: {
    // 初始化三维环境
    initThree() {
      this.initScene();
      this.initCamera();
      this.initRenderer();
      this.initControls();
    },
    // 获取画布尺寸
    getCanvasSize() {
      if (!this.container) this.container = document.getElementById("three");
      this.canvasWidth = this.container.offsetWidth;
      this.canvasHeight = this.container.offsetHeight;
    },
    // 初始化相机
    initCamera() {
      this.camera = new THREE.PerspectiveCamera(
        50, // fov
        this.canvasWidth / this.canvasHeight, // 纵横比
        0.5, // near
        1000 // far
      );
      this.camera.position.z = 10;
    },
    // 初始化场景
    initScene() {
      this.scene = new THREE.Scene();
      this.scene.background = new THREE.Color("#f6f6f6"); // 背景色
    },
    // 初始化渲染器
    initRenderer() {
      this.renderer = new THREE.WebGLRenderer({ antialias: true });
      this.resizeEvent();
      this.container.appendChild(this.renderer.domElement);
    },
    // 注册控制器
    initControls() {
      this.controls = new OrbitControls(this.camera, this.renderer.domElement);
      this.controls.addEventListener("change", this.render);
    },
    // 加载画布内容
    loadContent() {
      // 绘制初始内容
    },
    // 创建光源
    createLight() {
      this.canvasContent.basics.light = new THREE.DirectionalLight(0xffffff, 1);
      this.canvasContent.basics.light.position.set(100, 100, 100);
      // light.castShadow = true;    // 阴影
      this.scene.add(this.canvasContent.basics.light);
      this.scene.add(new THREE.AmbientLight(0xcccccc));
    },
    // 渲染函数
    render() {
      this.renderer.render(this.scene, this.camera);
    },
    // 更新坐标系
    updateAxesHelper(size) {
      if (this.canvasContent.basics.axesHelper)
        this.scene.remove(this.canvasContent.basics.axesHelper);
      if (this.canvasContent.geometries.length) {
        this.canvasContent.basics.axesHelper = new THREE.AxesHelper(size);
        this.scene.add(this.canvasContent.basics.axesHelper);
      }
      this.render();
    },
    // 更新地面
    updateGround() {
      if (this.canvasContent.basics.ground)
        this.scene.remove(this.canvasContent.basics.ground);
      if (!this.canvasContent.geometries.length) return;

      const { w, h } = this.groundSize;

      const planeSize = Math.max(w * 1.5, h * 1.5) + 5;
      const planeGeometry = new THREE.PlaneGeometry(planeSize, planeSize);
      const planeMaterial = new THREE.MeshStandardMaterial({ color: 0xbaccd9 }); // 云水蓝

      this.canvasContent.basics.ground = new THREE.Mesh(
        planeGeometry,
        planeMaterial
      );
      this.canvasContent.basics.ground.rotation.x = -0.5 * Math.PI;
      this.canvasContent.basics.ground.position.x = w / 2;
      this.canvasContent.basics.ground.position.z = h / 2;

      this.scene.add(this.canvasContent.basics.ground);
      this.render();
    },
    // 窗口尺寸变动事件函数
    resizeEvent() {
      this.getCanvasSize();
      this.camera.aspect = this.canvasWidth / this.canvasHeight;
      this.camera.updateProjectionMatrix();
      this.renderer.setSize(this.canvasWidth, this.canvasHeight);
      this.render();
    },
    // 绘制几何体
    drawGeometry(geometry) {
      // 创建包盒
      createBox3(geometry);
      // 将几何体加入数组
      this.canvasContent.geometries.push(geometry);
      // 更新画布
      this.updateGeometries(geometry);
    },
    // 删除几何体
    deleteGeometry(id) {
      const geometry = this.canvasContent.geometries[id];
      // 将几何体从数组中删除
      this.canvasContent.geometries.splice(id, 1);
      // 更新画布
      if (!this.canvasContent.geometries.length)
        this.adjustCameraPosition(0, 0, 10);
      this.updateGeometries(geometry);
    },
    updateGeometries(geometry) {
      // 更新画布尺寸
      this.updateCanvasSize();
      // 更新地面
      this.updateGround();
      if (geometry) {
        // 更新场景并重新渲染
        if (this.canvasContent.geometries.indexOf(geometry) !== -1) {
          this.scene.add(geometry);
        } else {
          this.scene.remove(geometry);
        }
      }
      this.render();
    },
    // 更新画布尺寸
    updateCanvasSize() {
      if (!this.canvasContent.geometries.length) {
        this.canvasPositionInfo.maxSize = 0;
        this.canvasPositionInfo.xRange.max = 0;
        this.canvasPositionInfo.yRange.max = 0;
        this.canvasPositionInfo.zRange.max = 0;
        this.canvasPositionInfo.xRange.min = 0;
        this.canvasPositionInfo.yRange.min = 0;
        this.canvasPositionInfo.zRange.min = 0;
        this.canvasPositionInfo.maxPosition = 0;
      }
      let maxSize = -1;
      let range = {
        x: {
          max: -Infinity,
          min: Infinity,
        },
        y: {
          max: -Infinity,
          min: Infinity,
        },
        z: {
          max: -Infinity,
          min: Infinity,
        },
      };
      for (const g of this.canvasContent.geometries) {
        const box3 = g.box3Info;
        const newMaxSize = Math.max(
          Math.abs(box3.min.x),
          Math.abs(box3.min.y),
          Math.abs(box3.min.z),
          Math.abs(box3.max.x),
          Math.abs(box3.max.y),
          Math.abs(box3.max.z)
        );
        if (newMaxSize > maxSize) maxSize = newMaxSize;
        if (box3.min.x < range.x.min) range.x.min = box3.min.x;
        if (box3.min.y < range.y.min) range.y.min = box3.min.y;
        if (box3.min.z < range.z.min) range.z.min = box3.min.z;
        if (box3.max.x > range.x.max) range.x.max = box3.max.x;
        if (box3.max.y > range.y.max) range.y.max = box3.max.y;
        if (box3.max.z > range.z.max) range.z.max = box3.max.z;
      }
      this.canvasPositionInfo.maxSize = maxSize;
      this.canvasPositionInfo.xRange.max = range.x.max;
      this.canvasPositionInfo.yRange.max = range.y.max;
      this.canvasPositionInfo.zRange.max = range.z.max;
      this.canvasPositionInfo.xRange.min = range.x.min;
      this.canvasPositionInfo.yRange.min = range.y.min;
      this.canvasPositionInfo.zRange.min = range.z.min;
      // 更新 maxPosition
      this.canvasPositionInfo.maxPosition = Math.max(
        this.canvasPositionInfo.xRange.max,
        this.canvasPositionInfo.yRange.max,
        this.canvasPositionInfo.zRange.max
      );
    },
    // 调整相机位置
    adjustCameraPosition(x, y, z) {
      this.camera.position.x = x;
      this.camera.position.y = y;
      this.camera.position.z = z;
      this.camera.lookAt({
        x: 0,
        y: 0,
        z: 0,
      });
      this.camera.zoom = 1;
      this.controls = new OrbitControls(this.camera, this.renderer.domElement);
      this.render();
    },
    // 切换至总览视图
    moveCameraToAll() {
      if (!this.canvasContent.geometries.length) return;
      this.adjustCameraPosition(
        this.canvasPositionInfo.maxPosition * 2.8,
        this.canvasPositionInfo.maxPosition * 3,
        this.canvasPositionInfo.maxPosition * 3
      );
    },
    // 切换至主视图
    moveCameraToFront() {
      if (!this.canvasContent.geometries.length) return;
      const cameraPos = this.canvasPositionInfo.maxPosition * 5;
      this.adjustCameraPosition(0, 0, cameraPos);
    },
    // 切换至侧视图
    moveCameraToRight() {
      if (!this.canvasContent.geometries.length) return;
      const cameraPos = this.canvasPositionInfo.maxPosition * 5;
      this.adjustCameraPosition(cameraPos, 0, 0);
    },
    // 切换至俯视图
    moveCameraToTop() {
      if (!this.canvasContent.geometries.length) return;
      const cameraPos = this.canvasPositionInfo.maxPosition * 5;
      this.adjustCameraPosition(0, cameraPos, 0);
    },
    //保存为图片
    saveCanvasTOPicture() {
      if (!this.canvasContent.geometries.length) return;
      this.render();
      const imgData = this.renderer.domElement.toDataURL("image/png");
      const link = document.createElement('a');
      link.href = imgData;
      link.download = 'threejs.png';
      link.click(); 
    },
  },
};
</script>

<style scoped>
#three {
  width: 100%;
  height: 100%;
  overflow: hidden;
}
</style>
